home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / utils / nroff~06.zoo / macros.c < prev    next >
C/C++ Source or Header  |  1992-07-16  |  11KB  |  595 lines

  1. static char *rcsid_macros_c="$Id: macros.c,v 1.2 1992/07/16 10:38:32 rosenkra Exp $";
  2.  
  3. /*
  4.  * $Log: macros.c,v $
  5.  * Revision 1.2  1992/07/16  10:38:32  rosenkra
  6.  * port to gcc, add tm,ie,el
  7.  *
  8.  */
  9.  
  10. /*
  11.  *    macros.c - macro input/output processing for nroff word processor
  12.  *
  13.  *    adapted for atariST/TOS by Bill Rosenkranz 11/89
  14.  *    net:    rosenkra@convex.com
  15.  *    CIS:    71460,17
  16.  *    GENIE:    W.ROSENKRANZ
  17.  *
  18.  *    original author:
  19.  *
  20.  *    Stephen L. Browning
  21.  *    5723 North Parker Avenue
  22.  *    Indianapolis, Indiana 46220
  23.  *
  24.  *    history:
  25.  *
  26.  *    - Originally written in BDS C;
  27.  *    - Adapted for standard C by W. N. Paul
  28.  *    - Heavily hacked up to conform to "real" nroff by Bill Rosenkranz
  29.  */
  30.  
  31. #undef NRO_MAIN                    /* extern globals */
  32.  
  33. #include <stdio.h>
  34. #include "nroff.h"
  35.  
  36.  
  37.  
  38. /*------------------------------*/
  39. /*    defmac            */
  40. /*------------------------------*/
  41. void defmac (p, infp)
  42. REGISTER char  *p;
  43. FILE           *infp;
  44. {
  45.  
  46. /*
  47.  *    Define a macro. top level, read from stream.
  48.  *
  49.  *    we should read macro without interpretation EXCEPT:
  50.  *
  51.  *    1) number registers are interpolated
  52.  *    2) strings indicated by \* are interpolated
  53.  *    3) arguments indicated by \$ are interpolated
  54.  *    4) concealed newlines indicated by \(newline) are eliminated
  55.  *    5) comments indicated by \" are eliminated
  56.  *    6) \t and \a are interpreted as ASCII h tab and SOH.
  57.  *    7) \\ is interpreted as backslash and \. is interpreted as a period.
  58.  *
  59.  *    currently, we do only 3. a good place to do it would be here before
  60.  *    putmac, after colmac...
  61.  */
  62.  
  63.     REGISTER char  *q;
  64.     REGISTER char  *ps;
  65.     REGISTER int    i;
  66.     char        name[MNLEN];
  67.     char        defn[MXMLEN];
  68.     char        newend[10];
  69.     char        ibuf[MAXLINE];
  70.  
  71.  
  72.     /*
  73.      *   skip the .de and get to the name...
  74.      */
  75.     q = skipwd (p);
  76.     q = skipbl (q);
  77.  
  78.     /*
  79.      *   ok, name now holds the name. make sure it is valid (i.e. first
  80.      *   char is alpha...). getwrd returns the length of the word.
  81.      */
  82.     i = getwrd (q, name);
  83.     if (!isprint (*name))
  84.     {
  85.         fprintf (err_stream,
  86.             "***%s: missing or illegal macro definition name\n",
  87.             myname);
  88.         err_exit (-1);
  89.     }
  90.  
  91.     /*
  92.      *   truncate to 2 char max name.
  93.      */
  94.     if (i > 2)
  95.         name[2] = EOS;
  96.  
  97.  
  98.     /*
  99.      *   skip the name and see if we have a new end defined...
  100.      */
  101.     q = skipwd (p);
  102.     q = skipbl (q);
  103.     q = skipwd (q);
  104.     q = skipbl (q);
  105.     for (i = 0; i < 10; i++)
  106.         newend[i] = EOS;
  107.  
  108.     for (i = 0; (i < 10) && ( isalpha (q[i]) || isdigit (q[i]) ); i++)
  109.     {
  110.         newend[i] = q[i];
  111.     }
  112.  
  113.  
  114.  
  115.     /*
  116.      *   read a line from input stream until we get the end of macro
  117.      *   command (.en or ..). actually. we should have read the next
  118.      *   field just above here to get the .de NA . or .de NA en string
  119.      *   to be new end of macro.
  120.      */
  121.     i  = 0;
  122.     ps = ibuf;
  123.     while (getlin (ps, infp) != EOF)
  124.     {
  125.         if (ps[0] == dc.cmdchr)
  126.         {
  127.             if (*(ps+1) == ' ' || *(ps+1) == '\t')
  128.             {
  129.                 ps    = skipbl (++ps);
  130.                 *--ps = dc.cmdchr;
  131.             }
  132.         }
  133.         if (ps[0] == dc.cmdchr && ps[1] == '\\' && ps[2] == '\"')
  134.         {
  135.             /*
  136.              *   comment, ignore it
  137.              */
  138.             continue;
  139.         }
  140.         if (ps[0] == dc.cmdchr && newend[0] != EOS
  141.         &&  ps[1] == newend[0] && ps[2] == newend[1])
  142.         {
  143.             /*
  144.              *   replacement end found
  145.              */
  146.             break;
  147.         }
  148.         if (ps[0] == dc.cmdchr && ps[1] == 'e' && ps[2] == 'n')
  149.         {
  150.             /*
  151.              *   .en found
  152.              */
  153.             break;
  154.         }
  155.         if (ps[0] == dc.cmdchr && ps[1] == dc.cmdchr)
  156.         {
  157.             /*
  158.              *   .. found
  159.              */
  160.             break;
  161.         }
  162.  
  163.  
  164.         /*
  165.          *   collect macro from the line we just read. all this does
  166.          *   is put it in the string defn.
  167.          */
  168.         if ((i = colmac (ps, defn, i)) == ERR)
  169.         {
  170.             fprintf (err_stream,
  171.                 "***%s: macro definition too long\n", myname);
  172.             err_exit (-1);
  173.         }
  174.  
  175.         ps = ibuf;
  176.     }
  177.  
  178.  
  179.     /*
  180.      *   store the macro
  181.      */
  182.     if (!ignoring)
  183.     {
  184.         if (putmac (name, defn) == ERR)
  185.         {
  186.             fprintf (err_stream,
  187.                 "***%s: macro definition table full\n", myname);
  188.             err_exit (-1);
  189.         }
  190.     }
  191. }
  192.  
  193.  
  194.  
  195.  
  196.  
  197. /*------------------------------*/
  198. /*    colmac            */
  199. /*------------------------------*/
  200. int colmac (p, d, i)
  201. REGISTER char  *p;
  202. char           *d;
  203. REGISTER int    i;
  204. {
  205.  
  206. /*
  207.  *    Collect macro definition from input stream
  208.  */
  209.  
  210.     char   *pstart = p;
  211.     int    istart = i;
  212.  
  213.     while (*p != EOS)
  214.     {
  215.         /*
  216.          *   are we over the length limit for a single macro?
  217.          */
  218.         if (i >= MXMLEN - 1)
  219.         {
  220.             d[i - 1] = EOS;
  221.             return (ERR);
  222.         }
  223.  
  224.         /*
  225.          *   "i break for comments..."
  226.          */
  227.         if (*p == '\\' && *(p+1) == '\"')
  228.         {
  229.             /*
  230.              *   first back over any whitespace between comment
  231.              *   start and last character in line. remember to
  232.              *   decrement counter i, too...
  233.              */
  234.             p--;
  235.             while (isspace (*p) && p > pstart && i > istart)
  236.             {
  237.                 p--;
  238.                 i--;
  239.             }
  240.  
  241.             /*
  242.              *   now skip over the comment until we reach the
  243.              *   trailing newline
  244.              */
  245.             while (*p != EOS)
  246.             {
  247.                 if (*p == '\n' || *p == '\r')
  248.                     break;
  249.                 p++;
  250.             }
  251.         }
  252.  
  253.         /*
  254.          *   skip quoted things
  255.          */
  256.         if (*p == '\\' && *(p+1) == '\\')
  257.             p++;
  258.  
  259.         /*
  260.          *   copy it
  261.          */
  262.         d[i++] = *p++;
  263.     }
  264.     d[i] = EOS;
  265.     return (i);
  266. }
  267.  
  268.  
  269.  
  270.  
  271.  
  272. /*------------------------------*/
  273. /*    putmac            */
  274. /*------------------------------*/
  275. int putmac (name, p)
  276. char   *name;
  277. char   *p;
  278. {
  279.  
  280. /*
  281.  *    Put macro definition into table
  282.  *
  283.  *    NOTE: any expansions of things like number registers SHOULD
  284.  *    have been done already.
  285.  */
  286.  
  287.  
  288.     /*
  289.      *   any room left? (did we exceed max number of possible macros)
  290.      */
  291.     if (mac.lastp >= MXMDEF)
  292.         return (ERR);
  293.  
  294.     /*
  295.      *   will new one fit in big buffer?
  296.      */
  297.     if (mac.emb + strlen (name) + strlen (p) + 1 > &mac.mb[MACBUF])
  298.     {
  299.         return (ERR);
  300.     }
  301.  
  302.  
  303.     /*
  304.      *   add it...
  305.      *
  306.      *   bump counter, set ptr to name, copy name, copy def.
  307.      *   finally increment end of macro buffer ptr (emb).
  308.      *
  309.      *   macro looks like this in mb:
  310.      *
  311.      *    mac.mb[MACBUF]        size of total buf
  312.      *    lastp < MXMDEF        number of macros possible
  313.      *    *mnames[MXMDEF]        -> names, each max length
  314.      *    ..._____________________________...____________________...
  315.      *        / / /|X|X|0|macro definition      |0| / / / / / / /
  316.      *    .../_/_/_|_|_|_|________________...___|_|/_/_/_/_/_/_/_...
  317.      *          ^
  318.      *          |
  319.      *          \----- mac.mnames[mac.lastp] points here
  320.      *
  321.      *   both the 2 char name (XX) and the descripton are null term and
  322.      *   follow one after the other.
  323.      */
  324.     ++mac.lastp;
  325.     mac.mnames[mac.lastp] = mac.emb;
  326.     strcpy (mac.emb, name);
  327.     strcpy (mac.emb + strlen (name) + 1, p);
  328.     mac.emb += strlen (name) + strlen (p) + 2;
  329.  
  330.     return (OK);
  331. }
  332.  
  333.  
  334.  
  335.  
  336.  
  337.  
  338. /*------------------------------*/
  339. /*    getmac            */
  340. /*------------------------------*/
  341. char *getmac (name)
  342. REGISTER char  *name;
  343. {
  344.  
  345. /*
  346.  *    Get (lookup) macro definition from namespace
  347.  */
  348.  
  349.     REGISTER int    i;
  350.  
  351.     /*
  352.      *   loop for all macros, starting with last one
  353.      */
  354.     for (i = mac.lastp; i >= 0; --i)
  355.     {
  356.         /*
  357.          *   is this REALLY a macro?
  358.          */
  359.         if (mac.mnames[i])
  360.         {
  361.             /*
  362.              *   if it compares, return a ptr to it
  363.              */
  364.             if (!strcmp (name, mac.mnames[i]))
  365.             {
  366. /*!!!debug            puts (mac.mnames[i]);*/
  367.  
  368.                 if (mac.mnames[i][1] == EOS)
  369.                     return (mac.mnames[i] + 2);
  370.                 else
  371.                     return (mac.mnames[i] + 3);
  372.             }
  373.         }
  374.     }
  375.  
  376.     /*
  377.      *   none found, return null
  378.      */
  379.     return (NULL_CPTR);
  380. }
  381.  
  382.  
  383.  
  384.  
  385.  
  386.  
  387. /*------------------------------*/
  388. /*    maceval            */
  389. /*------------------------------*/
  390. void maceval (p, m)
  391. REGISTER char  *p;
  392. char           *m;
  393. {
  394.  
  395. /*
  396.  *    Evaluate macro expansion
  397.  */
  398.  
  399.     REGISTER int    i;
  400.     char           *argp[15];
  401.     char        c;
  402.     int        xc;
  403.  
  404.  
  405.  
  406.     /*
  407.      *   replace command char with EOS
  408.      */
  409.     *p++ = EOS;
  410.  
  411.  
  412.     /* 
  413.      *   initialize argp array to substitute command
  414.      *   string for any undefined argument
  415.      *
  416.      *    NO!!! this is fixed...
  417.      */
  418. /*    for (i = 0; i < 10; ++i)
  419.         argp[i] = p;
  420. */
  421.     /*
  422.      *   skip the command name
  423.      */
  424.     p = skipwd (p);
  425.     *p++ = EOS;
  426.  
  427.  
  428.     /*
  429.      *   loop for all $n variables...
  430.      */
  431.     for (i = 0; i < 10; ++i)
  432.     {
  433.         /*
  434.          *   get to substituted param and if no more, reset remaining
  435.          *   args to NULL and stop. using "i" here IS ok...
  436.          */
  437.         p = skipbl (p);
  438.         if (*p == '\r' || *p == '\n' || *p == EOS)
  439.         {
  440.             if